<script setup lang="ts">
import { ref } from 'vue'
import HumbleiconsPlay from '~icons/humbleicons/play'
import HumbleiconsDotsHorizontal from '~icons/humbleicons/dots-horizontal'
import CatImage from '@renderer/components/CatImage.vue'
import { useArtistStore } from '@renderer/stores/artist'
import { useRoute, useRouter } from 'vue-router'
import dayjs from 'dayjs'
import { storageLocal } from '@renderer/tools/index'
import axios from 'axios'
import ContextMenu from '@renderer/components/ContextMenu.vue'
import { useFavoriteStore } from '@renderer/stores/favorite'

import type { ArtistInfo, TrackInfo, AlbumInfo, AlbumTrackData } from './type'

interface CollectionInfo {
  mid: number
  seasonid: number
  cover: string
  title: string
  songcount: number
  pubdate: number
  description: string
}

const { getArtistInfo, getAlbums, getAlbumInfo } = useArtistStore()
const route = useRoute()
const router = useRouter()
const mid = Number(route.params.mid)
const info = ref<ArtistInfo>()
const collections = ref<CollectionInfo[]>([])
const contextMenuRef = ref<InstanceType<typeof ContextMenu>>()
const { addPlaylist } = useFavoriteStore()

init()

async function init() {
  await getView()
  await generateAlbums()
}

async function getView() {
  const data = await getArtistInfo(mid)
  if (data) {
    const info_ = {
      cover: data.face,
      name: data.name,
      description: data.sign
    }
    info.value = info_
  }
}

async function generateAlbums() {
  const list = await getAlbums(mid)
  collections.value = list.map(({ meta }) => ({
    mid: meta.mid,
    seasonid: meta.season_id,
    cover: meta.cover,
    title: meta.name,
    songcount: meta.total,
    pubdate: meta.ptime,
    description: meta.description
  }))
}

async function doCollection(data: CollectionInfo) {
  const trackData = await generateTrackData(data)
  storageLocal().setItem('track-album', trackData)
  router.push({ name: 'track-album' })
}

async function generateTrackData(data: CollectionInfo) {
  try {
    if (!info.value) throw new Error('无法获取艺人信息')
    const info_: AlbumInfo = {
      cover: data.cover,
      title: data.title,
      author: info.value.name,
      pubdate: data.pubdate,
      description: data.description,
      songcount: data.songcount
    }

    // 获取专辑内歌曲信息，但没有歌曲cid
    const albumInfo: any[] = []
    const pagesize = 100
    for (let i = 0; i < Math.ceil(data.songcount / pagesize); i++) {
      const pagenum = i + 1
      const list = await getAlbumInfo({
        mid: data.mid,
        seasonid: data.seasonid,
        pagenum,
        pagesize
      })
      albumInfo.push(...list)
    }

    // 获取专辑内歌曲cid
    let cidList: any[] = []
    const url = 'https://www.bilibili.com/video/' + albumInfo[0].bvid
    const response = await axios.get(url)
    const reg = /window\.__INITIAL_STATE__=(.*?);\(function/i
    const match: RegExpExecArray | null = reg.exec(response.data)
    if (match) {
      const data = JSON.parse(match[1])
      cidList = data.availableVideoList
    }

    // 生成track-album需要的数据结构
    const tracks_ = albumInfo.map((item) => {
      const cover = item.pic.replace(/^http:/i, 'https:')
      const target = cidList.find((f) => f.bvid === item.bvid)
      const track: TrackInfo = {
        bvid: item.bvid,
        cid: target.cid,
        cover,
        title: item.title,
        author: info.value!.name,
        duration: item.duration
      }
      return track
    })

    const trackData: AlbumTrackData = {
      info: info_,
      tracks: tracks_
    }
    return trackData
  } catch (e) {
    if (e instanceof Error) {
      console.error(e.message)
    } else {
      console.error(e)
    }
  }
  return null
}

async function addToOwnPlay(data: CollectionInfo) {
  const trackData = await generateTrackData(data)
  if (trackData) {
    addPlaylist(trackData)
  }
}
</script>

<template>
  <ContextMenu ref="contextMenuRef" v-slot="{ data }: { data: CollectionInfo }">
    <div class="item" @click="addToOwnPlay(data)">添加到歌单</div>
  </ContextMenu>
  <div v-if="info" class="list-info">
    <div class="cover">
      <CatImage :src="info.cover" :width="512" :height="512" />
    </div>
    <div class="info">
      <div class="title">{{ info.name }}</div>
      <div class="artist">艺人</div>
      <div class="date-and-count">{{ 0 }} 首歌 · {{ collections.length }} 个专辑</div>
      <div class="description" :title="info.description">{{ info.description }}</div>
      <div class="buttons">
        <button class="blue">
          <HumbleiconsPlay class="svg-icon" />
          播放
        </button>
        <button class="grey">
          <HumbleiconsDotsHorizontal class="svg-icon" />
        </button>
      </div>
    </div>
    <div></div>
  </div>
  <div v-if="collections.length" class="albums">
    <div class="section-title">专辑</div>
    <div class="cover-row">
      <div
        v-for="item in collections"
        :key="item.seasonid"
        class="item"
        @click="doCollection(item)"
        @contextmenu.prevent="(e) => contextMenuRef?.open(e, item)"
      >
        <CatImage :src="item.cover" :width="200" :height="200" />
        <div class="text">
          <div class="title" :title="item.title">{{ item.title }}</div>
          <div class="info">
            {{ dayjs.unix(item.pubdate).format('YYYY年MM月DD日') }} · {{ item.songcount }} 首歌
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped lang="less">
.list-info {
  display: flex;
  margin-bottom: 42px;
  position: relative;
  .cover {
    @width: 248px;
    width: @width;
    height: @width;
    img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      border-radius: 50%;
      border: 1px solid rgba(0, 0, 0, 0.04);
      &[src=''] {
        display: none;
      }
    }
  }
  .info {
    display: flex;
    flex-direction: column;
    justify-content: center;
    flex: 1;
    overflow: auto;
    margin-left: 56px;
    .title {
      font-size: 36px;
      font-weight: 700;
      color: var(--color-text);
    }
    .artist {
      font-size: 18px;
      opacity: 0.88;
      color: var(--color-text);
      margin-top: 24px;
    }
    .date-and-count {
      font-size: 14px;
      opacity: 0.68;
      color: var(--color-text);
      margin-top: 2px;
    }
    .description {
      font-size: 14px;
      opacity: 0.68;
      color: var(--color-text);
      margin-top: 24px;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      line-clamp: 3;
      -webkit-line-clamp: 3;
      overflow: hidden;
    }
    .buttons {
      margin-top: 32px;
      display: flex;
      button {
        border-radius: 8px;
        padding: 8px 16px;
        width: auto;
        margin: 0;
        margin-right: 16px;
        height: 40px;
        min-width: 40px;
        font-size: 18px;
        line-height: 18px;
        font-weight: 600;
      }
      .blue {
        background-color: var(--color-primary-bg);
        color: var(--color-primary);
        .svg-icon {
          margin: -6px;
          margin-right: 4px;
          @width: 26px;
          width: @width;
          height: @width;
          color: var(--color-primary);
        }
      }
      .grey {
        background-color: var(--color-secondary-bg);
        color: var(--color-text);
        opacity: 0.78;
        .svg-icon {
          margin: -6px;
        }
      }
    }
  }
}
.albums {
  .section-title {
    font-weight: 600;
    font-size: 22px;
    opacity: 0.88;
    color: var(--color-text);
    margin-bottom: 16px;
  }
  .cover-row {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 44px 24px;
    .item {
      color: var(--color-text);
      img {
        width: 100%;
        border-radius: 0.75em;
        border: 1px solid rgba(0, 0, 0, 0.04);
      }
      .text {
        margin-top: 8px;
        .title,
        .info {
          display: -webkit-box;
          -webkit-box-orient: vertical;
          line-clamp: 2;
          -webkit-line-clamp: 2;
          overflow: hidden;
        }
        .title {
          font-weight: 600;
          line-height: 20px;
          word-break: break-all;
        }
        .info {
          font-size: 12px;
          opacity: 0.68;
          line-height: 18px;
          word-break: break-word;
        }
      }
    }
  }
}
</style>
